package com.ljx.funchat.sensitive.algorithm;

import com.ljx.funchat.sensitive.dao.SensitiveWordDao;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * Trie树算法的实现类
 */
@Component
public class TrieSearcher {

    private final SensitiveWordDao sensitiveWordDao;

    public TrieSearcher(SensitiveWordDao sensitiveWordDao){
        this.sensitiveWordDao = sensitiveWordDao;
    }

    private TrieNode root = new TrieNode();

    /**
     * 添加词
     *
     * @param word 词
     */
    public void addWord(String word) {
        TrieNode tmpTrieNode = root;
        for (char c : word.toCharArray()) {
            // 查找该结点是否存在子节点
            TrieNode trieNode = tmpTrieNode.getNext(c);
            if (Objects.isNull(trieNode)) {
                // 不存在就添加一个
                trieNode = new TrieNode();
                tmpTrieNode.addNext(c, trieNode);
            }
            // 将父节点重新赋值
            tmpTrieNode = trieNode;
        }
    }

    /**
     * 替换词
     *
     * @param text         待处理文本
     * @param afterReplace 替换后的词
     * @return 处理后的文本
     */
    public String replace(String text, String afterReplace) {
        StringBuilder result = new StringBuilder(text.length());
        TrieNode tmpTrieNode = root;
        // begin用于获取正常字符的辅助下标，pos是text下标
        int begin = 0, pos = 0;
        while (pos < text.length()) {
            char c = text.charAt(pos);
            tmpTrieNode = tmpTrieNode.getNext(c);
            if (Objects.isNull(tmpTrieNode)) {
                // 该字符不是敏感词，直接添加到结果
                result.append(text.charAt(begin));
                begin ++;
                pos = begin;
                pos ++;
                tmpTrieNode = root;
            } else if (tmpTrieNode.isLastCharacter()) {
                // 是敏感词并且是最后一个字符，替换为相应的字符
                result.append(afterReplace);
                pos ++;
                begin = pos;
                tmpTrieNode = root;
            } else {
                // 匹配上向后移
                pos ++;
            }
        }
        result.append(text.substring(begin));
        return result.toString();
    }

    /**
     * 查找
     *
     * @param text 待处理文本
     * @return 统计数据 key: word value: count
     */
    public Map<String, Integer> find(String text) {
        Map<String, Integer> resultMap = new HashMap<>(16);
        TrieNode tmpTrieNode = root;
        StringBuilder word = new StringBuilder();
        int begin = 0, pos = 0;
        while (pos < text.length()) {
            char c = text.charAt(pos);
            tmpTrieNode = tmpTrieNode.getNext(c);
            if (null == tmpTrieNode) {
                begin++;
                pos = begin;
                tmpTrieNode = root;
            } else if (tmpTrieNode.isLastCharacter()) {
                // 匹配完成
                String w = word.append(c).toString();
                resultMap.put(w, resultMap.getOrDefault(w, 0) + 1);
                pos++;
                begin = pos;
                tmpTrieNode = root;
                word = new StringBuilder();
            } else {
                // 匹配上向后移
                word.append(c);
                pos++;
            }
        }
        return resultMap;
    }

    @PostConstruct
    public void init(){
        List<String> sensitiveWordList = sensitiveWordDao.getSensitiveWordList();
        sensitiveWordList.stream().forEach(this::addWord);
    }
}